from bge import logic as g
import bge
 
"""
	States
	1 run to location
	2 dead
	3 idle
	4 atk and rotate to target
	5 chase target
	6 use Skill

	x social action


	TODO

		SFX lorsque l'enemy meurt, le son s'arrete net, il devrait continuer normalement
		OSEF afficher les dégats
		Console comme dans L2

		Nettoyer les scripts python
		Tout le système d'animation doit etre changé.
		Les animations de chaque state doivent etre lancées par une brique Logique qui ne se lance qu'une fois.
		Et le script python associé au state ne fait que scanner chaque frame pour détécter les changements de state et effectuer les actions intrinsèques au state en cours.
		Le script ne doit pas s'occuper de lancer des animations, au pire il peut activer un actuateur d'animation, si l'animation en cours est nulle.



		Il y a des actions qui edoivent s'effectuer en plusieurs states
		- Lorsque l'on utilise un skill après avoir selectionné une cible
			il faut courir jusque la cible et lancer le skill lorsqu'elle est à portée
				doit on créer un state chaseForSkill, qui s'occupera de lancer le skill au moment voulu ?
				ou bien mémoriser l'action à effectuer, lancer le state chase et lorsque la phase d'attaque arrive, lancer le skill mémorisé


				
		completer les enchainements de states
			Un enchainement peut se faire, au tout debut du state, ou tout à la fin, lorsque l'action est terminée.
				Selon l'importance de la raison du changement
					Si le mob meurt, l'action doit s'arreter, on doit stopper net. En revanche, si on change de Mob, il n'est pas nécéssaire de stopper net, on termine  l'action en cours
					La transition vers die s'effectue tjr en première position, on ne voudrait pas continuer ou commencer une action alors que l'on est mort entre temps.
				

			NON [Lorsque l'on chase, il se peut que l'on souhaite directement effectuer un skill au lieu de vouloir l'attaquer normalement]
				il vaut mieux ecrire un message "Target out of range" lorsque l'on essaie de lancer un skill sur une cible trop loin, cela evite de lui courir après automatiquement et de coder cette partie
			??? [L'intention du joueur doit etre prise en compte dans une variable, chaseForSkill, SkillTarget ?]
				??? L'intention peut elle etre générale ? une meme variable utilisée pour tous les states, ou bien doit on créer un state spécifique.
			
			OUI SelectedTarget et target :
				Changer le state de manière différente en fonction de target et selectedTarget, et en fonction de l'action désirée


		run - die (HP)
		run - idle (location)
		run - chase ( SelectedTarget, déclenché par[gui click | hotkey], Goal = atk | Skill en fonction de l'input gui/hotkey)
		run - idle (Action cancel, Gui ou hotkey)
		run - SkillSelf (self, gui click ou hotkey, Goal = run)

		idle - die (hp)
		idle - idle (Loop)
		idle - run (location click)
		idle - chase ( SelectedTarget[Mob], déclenché par[gui click | hotkey], Goal = atk | skill )
		idle - chase (aggro nearest Mob, au bout de X secondes, Goal = atk)
		idle - SkillSelf (self, gui click ou hotkey, Goal = idle)

		chase - die (HP)
		chase - atk (proximité Mob, Goal == atk)
		chase - Skill (proximité Mob, Goal == Skill)
		chase - SkillSelf (self, goal = chaseToSkill ou goal = chaseToAtk en fonction de goal)
		chase - idle (Mob dead)
		chase - idle (Mob out of range)
		chase - idle (Action cancel, hotkey echap)
		chase - Chase (SelectedTarget[Mob], déclenché par[gui click | hotkey], Goal = atk | skill)

		atk - die (hp)
		atk - idle (action cancel gui hotkey
		atk - chase (Gui | hotkey, goal = Skill)
		atk - chase (selected, déclenché par[gui click | hotkey], Goal = atk | skill)
		atk - chase (default loop, target, Goal = atk)

		Skill - die (Hp)
		Skill - idle (mob dead)
		Skill - idle (Action cancel, Gui ou hotkey)
		Skill - Run (Gui click location)
		Skill - chase (Gui new target, déclenché par[gui click | hotkey], Goal = atk | skill)
		Skill - SkillSelf (self, goal = chase)
		Skill - chase ( default loop target, Goal = atk)
		
		SkillSelf - chase (goal = Skill | atk en fonction de goal == chaseToSkill ou ChaseToAtk)
		SkillSelf - idle (Action cancel, gui hotkey)
		SkillSelf - idle (goal == idle) action par defaut, meme pas besoin de goal pour ça
		SkillSelf - Run (goal = run)
		SkillSelf - atk (goal = atk)
		
		
		SkillAoe - die
		SkillAoe - idle (defaut)
		SkillAoe - idle (cancel)
		SkillAoe - SkillAoe (gui hotkey, zone selected)


"""

def chaseTarget(cont):
	o = cont.owner
	player_armature = g.getCurrentScene().objects.get("Armature")
	enemy_cube = g.getCurrentScene().objects.get("enemy_cube")
	
	player_cube = g.getCurrentScene().objects.get("Cube")
	player_cube["active_state"] = "chaseTarget"
	
	#si je suis dead
	if player_cube["hp"] <= 0 :
		chaseToDie = cont.actuators["chaseToDie"]
		print("goto chaseToDie")
		cont.activate(chaseToDie)
	
	distance = o.getDistanceTo(enemy_cube)
	
	#si on a cliqué sur le sol pour arreter la poursuite
	if player_cube["chaseTarget"] == False :
		#on passe en mode runToLocation
		chaseToRun = cont.actuators["chaseToRun"]
		print("goto chaseToRun")
		cont.activate(chaseToRun)
	
	#si on etait au repos
	#si on est en train de courir 
	if not player_armature["current_action"] == "stv_hero_run" :
		player_armature.stopAction()
		player_armature.playAction("stv_hero_run", 0, 20, 0, 1, 4, bge.logic.KX_ACTION_MODE_LOOP, 0.0, 0, 1.0)
		player_armature["current_action"] = "stv_hero_run"
	
	#si par hasard on se gratte le cul
	if not player_armature.isPlayingAction():
		player_armature.playAction("stv_hero_run", 0, 20, 0, 1, 4, bge.logic.KX_ACTION_MODE_LOOP, 0.0, 0, 1.0)
		player_armature["current_action"] = "stv_hero_run"

	#si le gars est assez proche on le bute
	if distance < 2 :
		chaseToAtk = cont.actuators["chaseToAtk"]
		print("goto chaseToAtk")
		cont.activate(chaseToAtk)
	
def useSkill(cont):

	player_cube = g.getCurrentScene().objects.get("Cube")
	player_armature = g.getCurrentScene().objects.get("Armature")
	enemy_cube = g.getCurrentScene().objects.get("enemy_cube")
	
	
	#si je suis dead
	if player_cube["hp"] <= 0 :
		skillToDie = cont.actuators["skillToDie"]
		print("goto skillToDie")
		cont.activate(skillToDie)
	
	#si l'ennemy est mort   
	if enemy_cube["hp"] <= 0 :
		skillToIdle = cont.actuators["skillToIdle"]
		player_cube["runToLocation"] = False
		print("goto skillToIdle mort")
		
		#on doit supprimer les vfx
		if(player_cube["fxShineName"] != "dead") :
			ob = g.getCurrentScene().objects.get(player_cube["fxShineName"])
			player_cube["fxShineName"] = "dead"
			ob.endObject()
		if(player_cube["fxAccName"] != "dead") :
			ob = g.getCurrentScene().objects.get(player_cube["fxAccName"])
			player_cube["fxAccName"] = "dead"
			ob.endObject()
		
		cont.activate(skillToIdle)
	
	#si on est en pleine action
	if(player_armature["current_action"] == player_cube["current_skill"]):
		
		#création vfx accumulation 6 - 23
		if player_armature.getActionFrame() >= 6 :
			
			if player_cube["canAccumulate"] == True :
				player_cube["canAccumulate"] = False
				
				#vfx accumulation
				#ob = g.getCurrentScene().addObject("stv_particle_starburst_03", "stv_particle_starburst_03", 17)
				ob = g.getCurrentScene().addObject("stv_particle_starburst_03", "stv_particle_starburst_03")
				bone = g.getCurrentScene().objects.get("Sphere")
				ob.position = bone.position
				ob.worldOrientation = bone.worldOrientation
				
				player_cube["fxAccName"] = ob.name
		
		#mise à jour du vfx accumulation
		if player_armature.getActionFrame() >= 6 and player_armature.getActionFrame() <= 23 :
			ob = g.getCurrentScene().objects.get(player_cube["fxAccName"])
			bone = g.getCurrentScene().objects.get("Sphere")
			ob.position = bone.position
			ob.worldOrientation = bone.worldOrientation
			
		#suppression du vfx accumulation
		if player_armature.getActionFrame() > 23 :
			if(player_cube["fxAccName"] != "dead") :
				print("wtf")
				ob = g.getCurrentScene().objects.get(player_cube["fxAccName"])
				player_cube["fxAccName"] = "dead"
				ob.endObject()
		
		#Dague chargée 20 - 28
		#création vfx shine 20 - 28
		if player_armature.getActionFrame() >= 20 :
			
			if player_cube["canShine"] == True :
				player_cube["canShine"] = False
				
				#vfx shine
				ob = g.getCurrentScene().addObject("stv_particle_starburst", "stv_particle_starburst")
				bone = g.getCurrentScene().objects.get("Sphere")
				ob.position = bone.position
				ob.worldOrientation = bone.worldOrientation
				
				player_cube["fxShineName"] = ob.name
		#mise à jour du vfx shine
		if player_armature.getActionFrame() >= 20 and player_armature.getActionFrame() <= 28 :
			ob = g.getCurrentScene().objects.get(player_cube["fxShineName"])
			bone = g.getCurrentScene().objects.get("Sphere")
			ob.position = bone.position
			ob.localscale.x = 0.3
			ob.localscale.y = 0.3
			ob.localscale.z = 0.3
			ob.worldOrientation = bone.worldOrientation
		#suppression du vfx shine
		if player_armature.getActionFrame() > 28 :
			if(player_cube["fxShineName"] != "dead") :
				print("wtf")
				ob = g.getCurrentScene().objects.get(player_cube["fxShineName"])
				player_cube["fxShineName"] = "dead"
				ob.endObject()
		
		
		#moment de l'impact
		if player_armature.getActionFrame() >= 26 :	
			if player_cube["canHit"] == True :
				#print("player > prend ça !")
				player_cube["canHit"] = False
				#TODO damages du skill, effets associés (effect manager, etc)
				enemy_cube["hp"] -= 10
				
				#TODO show vfx
				
				#SFX sfx_energy_impact
				sfx_impact = cont.actuators["sfx_energy_impact"]
				cont.activate(sfx_impact)
				sfx_impact = cont.actuators["sfx_sword_hit_01"]
				cont.activate(sfx_impact)
				
				#id enemy is dead
				if enemy_cube["hp"] < 0 :
					enemy_cube["hp"] = 0
	#duree33	
	
	#si on frappe pas déjà alors on engage le combat  (première fois)	  
	if not player_armature["current_action"] == player_cube["current_skill"] :
		player_armature.playAction(player_cube["current_skill"], 0, 33, 0, 1, 4, bge.logic.KX_ACTION_MODE_PLAY, 0.0, 0, 1.0)
		player_armature["current_action"] = player_cube["current_skill"]
		player_cube["canHit"] = True
		player_cube["canAccumulate"] = True
		player_cube["canShine"] = True
		
		#SFX charge
		sfx_charge = cont.actuators["sfx_charge"]
		cont.activate(sfx_charge)
	
	
	#Animation par defaut si on a rien d'autre en cours fallback animation
	if not player_armature.isPlayingAction():
		#on a terminé le skill, on retourne en mode atk
		skillToAtk = cont.actuators["skillToAtk"]
		print("goto skillToAtk")
		cont.activate(skillToAtk)
		player_cube["canHit"] = True
		
def atk(cont):
	#print("aller attaque ducon")
	
	keyboard = bge.logic.keyboard
	
	o = cont.owner	
	
	player_armature = g.getCurrentScene().objects.get("Armature")
	enemy_cube = g.getCurrentScene().objects.get("enemy_cube")
	
	player_cube = g.getCurrentScene().objects.get("Cube")
	player_cube["active_state"] = "atk"
	
	#si je suis dead
	if player_cube["hp"] <= 0 :
		atkToDie = cont.actuators["atkToDie"]
		print("goto atkToDie")
		cont.activate(atkToDie)
	
	#si l'ennemy est mort   
	if enemy_cube["hp"] <= 0 :
		atkToIdle = cont.actuators["atkToIdle"]
		player_cube["runToLocation"] = False
		print("goto atkToIdle mort")
		cont.activate(atkToIdle)
	
	#Si j'ai décidé de lancer un skill
	#TODO vérifier les conditions requises pour lancer ce skill, quantité de mana, etc
	aKey = bge.logic.KX_INPUT_ACTIVE == keyboard.events[bge.events.AKEY]
	if aKey:
		atkToSkill = cont.actuators["atkToSkill"]
		player_cube["current_skill"] = "stv_hero_stab_01"
		print("goto atkToSkill")
		cont.activate(atkToSkill)
	
		
	distance = o.getDistanceTo(enemy_cube)
	#si l'enemy est trop loin
	if distance > 4 :
		atkToChase = cont.actuators["atkToChase"]
		cont.activate(atkToChase)
		print("goto atkToChase")
	
	
	#si on est en pleine action
	if(player_armature["current_action"] == "stv_hero_dagger_hit_01"):
		if player_armature.getActionFrame() >= 20 :
			#toucher l'enemi !!
			if o["canHit"] == True :
				
				print("aller frappe le ducon")
				damages = player_cube["patk"] - enemy_cube["pdef"]
				
				if damages < 0 :
					damages = 0
				
				enemy_cube["hp"] -= damages
				
				if enemy_cube["hp"] < 0 :
					enemy_cube["hp"] = 0
					
					player_cube["chaseTarget"] = False
					player_cube["target"] = "none"
					
				
				#VFX base impact
				ob = g.getCurrentScene().addObject("stv_particle_impact", "stv_particle_impact", 6)
				ob.position = enemy_cube.position
				ob.position.z += 1.2
				ob.worldOrientation = enemy_cube.worldOrientation
				#Play sound
				sfx_punch_01 = cont.actuators["sfx_punch_01"]
				cont.activate(sfx_punch_01)
				
				sfx_impact = cont.actuators["sfx_sword_hit"]
				cont.activate(sfx_impact)
				
				
				o["canHit"] = False
			
			
	#si on frappe pas déjà alors on engage le combat  (première fois)	  
	if not player_armature["current_action"] == "stv_hero_dagger_hit_01" :
		player_armature.playAction("stv_hero_dagger_hit_01", 0, 35, 0, 1, 4, bge.logic.KX_ACTION_MODE_PLAY, 0.0, 0, 1.0)
		player_armature["current_action"] = "stv_hero_dagger_hit_01"
		o["canHit"] = True
	
	
	#Animation par defaut si on a rien d'autre en cours fallback animation
	if not player_armature.isPlayingAction():
		player_armature.playAction("stv_hero_dagger_hit_01", 0, 35, 0, 1, 4, bge.logic.KX_ACTION_MODE_PLAY, 0.0, 0, 1.0)
		player_armature["current_action"] = "stv_hero_dagger_hit_01"
		o["canHit"] = True
		

def updateHpBar(cont):
	

	c = g.getCurrentController()

	#hp bar Object
	o = g.getCurrentScene().objects.get("hp_fond")
		
	distance = o.getDistanceTo(g.getCurrentScene().active_camera.position)
	
	
	scale = 1 * distance/2.5 
	
	o.localScale.x = scale
	o.localScale.y = scale
	o.localScale.z = scale
	
	
	player_cube = g.getCurrentScene().objects.get("Cube")
	
	o.position = player_cube.position
	o.position.z += o["zOffset"]
	
	#update hp bar
	player = g.getCurrentScene().objects.get("Armature")
	hp_bar = g.getCurrentScene().objects.get("hp_bar")
	
	scale = player_cube["hp"] / player_cube["hp_max"]
	
	hp_bar.localScale.x = scale

	
def idle(cont):
	#print("player IDLE")
	player_armature = g.getCurrentScene().objects.get("Armature")
	player_cube = g.getCurrentScene().objects.get("Cube")
	enemy_cube = g.getCurrentScene().objects.get("enemy_cube")
	player_cube["active_state"] = "idle"
	
	own = cont.owner
	
	#si je suis dead
	if player_cube["hp"] <= 0 :
		idleToDie = cont.actuators["idleToDie"]
		print("goto idleToDie")
		cont.activate(idleToDie)
	
	
	#si on doit se bouger le cul
	if own["runToLocation"] == True :
		own["runToLocation"] = False
		print("goto idleToRun")
		idleToRun = cont.actuators["idleToRun"]
		cont.activate(idleToRun)
	
	#si j'ai cliqué sur un énemy avec la souris
	#la première fois, on affiche la barre d'hp_bar dans mouseClick
	#la seconde fois on lui cour après
	if player_cube["chaseTarget"] == True and enemy_cube["hp"] > 0:
		#on chase directement
		idleToChase = cont.actuators["idleToChase"]
		cont.activate(idleToChase)
		print("goto idleToChase")
		#TODO, dans le state chase, manipuler l'actuator steering pour lui faire prendre pour cible le target ici présent
	
	if not player_armature["current_action"] == "stv_hero_idle" :
		player_armature.playAction("stv_hero_idle", 0, 200, 0, 0, 4, bge.logic.KX_ACTION_MODE_LOOP, 0.0, 0, 1.0)
		player_armature["current_action"] = "stv_hero_idle"
	if not player_armature.isPlayingAction():		
		player_armature.playAction("stv_hero_idle", 0, 200, 0, 1, 4, bge.logic.KX_ACTION_MODE_LOOP, 0.0, 0, 1.0)
		player_armature["current_action"] = "stv_hero_idle" 
		print("fallback idle")	 
	
	
	#si je dois me déplacer
	if own["runToLocation"] == True :
		#Si je suis loin de ma destination
		o = cont.owner
		goal = g.getCurrentScene().objects.get("Goal")
		
		distance = o.getDistanceTo(goal)
		if distance > 1 :
			idleToRun = cont.actuators["idleToRun"]
			print("goto idleToRun")
			cont.activate(idleToRun)
	
	#si il y a un énemy vivant à proximité
	if enemy_cube["hp"] > 0 :
		distance = player_cube.getDistanceTo(enemy_cube)
		#si le player est trop loin
		if distance < 4 :
			atkToChase = cont.actuators["idleToChase"]
			
			own["runToLocation"] = False
			
			cont.activate(atkToChase)
			
			print("goto idleToChase")
	
	
def die(cont):

	player_cube = g.getCurrentScene().objects.get("Cube")
	player_cube["active_state"] = "die"
	
	player = g.getCurrentScene().objects.get("Armature")
	if not player["current_action"] == "stv_hero_die" :
		player.playAction("stv_hero_die", 0, 42, 0, 0, 4, bge.logic.KX_ACTION_MODE_PLAY, 0.0, 0, 1.0)
		player["current_action"] = "stv_hero_die"
	
 
def runToLocation(cont):
	
	#print("runToLocation !!!")
	
	#cont = bge.logic.getCurrentController()
	player_cube = cont.owner
	
	player_cube["active_state"] = "runToLocation"
	
	player_armature = g.getCurrentScene().objects.get("Armature")
	enemy_cube = g.getCurrentScene().objects.get("enemy_cube")
	
	
	#si je suis dead
	if player_cube["hp"] <= 0 :
		runToDie = cont.actuators["runToDie"]
		cont.activate(runToDie)
	
	#peu importe ce qui nous a amené dans ce state, on doit courir
	if not player_armature["current_action"] == "stv_hero_run" :
		
		#stop everything
		player_armature.setActionFrame(199)
		player_armature.stopAction()
		
		player_armature.playAction("stv_hero_run", 0, 20, 0, 1, 2, bge.logic.KX_ACTION_MODE_LOOP, 0.0, 0, 1.0)
		player_armature["current_action"] = "stv_hero_run"
		print("goto run") 
	if not player_armature.isPlayingAction():
		player_armature.stopAction(1)
		
		player_armature.playAction("stv_hero_run", 0, 20, 0, 1, 4, bge.logic.KX_ACTION_MODE_LOOP, 0.0, 0, 1.0)
		player_armature["current_action"] = "stv_hero_run" 
		print("fallback run") 
	
	
		
	#Si je suis arrivé à ma destination cible
	o = cont.owner
	goal = g.getCurrentScene().objects.get("Goal")
	
	distance = o.getDistanceTo(goal)

	if distance < 1 :
		runToIdle = cont.actuators["runToIdle"]
		cont.activate(runToIdle)

	"""
	#si je croise un enemy
	distance = o.getDistanceTo(enemy_cube)
	if distance < 4 and enemy_cube["hp"] > 0:
		runToAtk = cont.actuators["runToAtk"]
		cont.activate(runToAtk)
		print("goto runToAtk")
	"""	


